package cn.unknowpupil.init.service.system.impl;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.mail.Mail;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import cn.unknowpupil.init.common.constant.SecurityConstants;
import cn.unknowpupil.init.domain.dto.EmailDto;
import cn.unknowpupil.init.domain.system.SysEmail;
import cn.unknowpupil.init.domain.vo.EmailVo;
import cn.unknowpupil.init.exceptions.HealthException;
import cn.unknowpupil.init.mapper.system.SysEmailMapper;
import cn.unknowpupil.init.service.system.ISysEmailService;
import cn.unknowpupil.init.utils.EncryptUtils;
import cn.unknowpupil.init.utils.redis.RedisUtils;
import cn.unknowpupil.init.utils.strings.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created at 2020-11-04 by  w10g <br>
 * Initialize SysEmail  ... <br>
 *  邮件配置表 核心业务处理实现类
 *
 * @author unknowpupil
 * @since 0.0.1
 */
@Service
public class SysEmailServiceImpl extends ServiceImpl<SysEmailMapper, SysEmail> implements ISysEmailService {

    @Autowired
    private RedisUtils redisUtil;

        /**
         *  新增
         * @param sysEmail {@link SysEmail}  邮件配置表
         * @return {@link SysEmail}
         */
        @Override
        public  boolean create( SysEmail sysEmail ){
            boolean b = checkFromUserUnique(sysEmail);
            if (!b) {
                throw new HealthException("新增邮件配置'" + sysEmail.getFromUser() + "'失败， 发件人已存在");
            }
            // 默认关闭
            sysEmail.setStatus("1");
            try {
                String s = EncryptUtils.desEncrypt(sysEmail.getPass());
                sysEmail.setPass(s);
            } catch (Exception e) {
                log.error("【对称加密失败】----------失败原因：{}",e);
                throw new HealthException("新增失败，对称加密失败");
            }
            return save(sysEmail);
        }

        /**
         *  详情
         * @param id {@code Long}   SysEmail ID
         * @return {@link SysEmail}
         */
        @Override
        public  SysEmail info(Long id){
            return getById(id);
        }

        /**
         *  删除
         * @param ids {@code Long}   ids
         * @return {@link SysEmail}
         */
        @Override
        public  boolean delete(Long[] ids){
            int count = count();
            if(count==ids.length){
                throw new HealthException("不能全部删除");
            }

            for (Long id : ids) {
                SysEmail sysEmail = getById(id);
                if(SecurityConstants.IS_OPEN.equals(sysEmail.getStatus())){
                    throw new HealthException("删除邮件配置下有开启配置的选项，无法删除");
                }
            }

            List<Long> collect = Stream.of(ids).collect(Collectors.toList());
            return removeByIds(collect);
        }


        /**
         *  修改
         * @param sysEmail {@link SysEmail}  邮件配置表
         * @return {@link SysEmail}
         */
        @Override
        public  boolean update( SysEmail sysEmail ){
            boolean b = checkFromUserUnique(sysEmail);
            if (!b) {
                throw new HealthException("修改邮件配置'" + sysEmail.getFromUser() + "'失败， 发件人已存在");
            }
            SysEmail byId = getById(sysEmail.getId());
            if(!byId.getPass().equals(sysEmail.getPass())){
                try {
                    sysEmail.setPass(EncryptUtils.desEncrypt(sysEmail.getPass()));
                } catch (Exception e) {
                    log.error("【对称加密失败】----------失败原因：{}",e);
                    throw new HealthException("修改失败，对称加密失败");
                }
            }

            return updateById(sysEmail);
        }


        /**
         * 分页
         * @param current {@code int} 页码
         * @param size {@code int} 笔数
         * @param sysEmail {@link SysEmail}
         * @return {@code IPage<SysEmail>}
         */
        @Override
        public IPage<SysEmail> page(int current, int size, SysEmail sysEmail){
            IPage<SysEmail> page = new Page<>(current, size);
            LambdaQueryWrapper<SysEmail> wrapper = new LambdaQueryWrapper<>();
            if(StringUtils.isNotBlank(sysEmail.getUser())){
                wrapper.like(SysEmail::getUser,sysEmail.getUser());
            }
            if(StringUtils.isNotBlank(sysEmail.getFromUser())){
                wrapper.like(SysEmail::getFromUser,sysEmail.getFromUser());
            }
            return super.page(page, wrapper);
        }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void send(EmailVo emailVo, SysEmail sysEmail){
        if(sysEmail == null){
            throw new HealthException("请先配置，再操作");
        }
        // 封装
        MailAccount account = new MailAccount();
        account.setUser(sysEmail.getUser());
        account.setHost(sysEmail.getHost());
        account.setPort(Integer.parseInt(sysEmail.getPort()));
        account.setAuth(true);
        try {
            // 对称解密
            String pass = EncryptUtils.desDecrypt(sysEmail.getPass());
            account.setPass(pass);
        } catch (Exception e) {
            throw new HealthException(e.getMessage());
        }
        account.setFrom(sysEmail.getUser()+"<"+sysEmail.getFromUser()+">");
        // ssl方式发送
        account.setSslEnable(true);
        // 使用STARTTLS安全连接
        account.setStarttlsEnable(true);
        String content = emailVo.getContent();
        // 发送
        try {

            Mail.create(account)
                    .setTos(emailVo.getTos())
                    .setTitle(emailVo.getSubject())
                    .setContent(content)
                    .setHtml(true)
                    //关闭session
                    .setUseGlobalSession(false)
                    .send();
        }catch (Exception e){
            throw new HealthException(e.getMessage());
        }
    }

    @Override
    public SysEmail find() {
        SysEmail sysEmail = baseMapper.selectStatusOpenConfigure();
            return sysEmail;
    }

    @Override
    public EmailVo sendEmail(String email, String key) {
        EmailVo emailVo;
        String content;
        String redisKey = key + email;
        // 如果不存在有效的验证码，就创建一个新的
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("email/email.ftl");
        Object oldCode =  redisUtil.get(redisKey);
        if(oldCode == null){
            String code = RandomUtil.randomNumbers (6);
            // 存入缓存
            if(!redisUtil.set(redisKey, code, SecurityConstants.EXPIRE_CODE_SECONDS)){
                throw new HealthException("服务异常，请联系网站负责人");
            }
            content = template.render(Dict.create().set("code",code));
            emailVo = new EmailVo(email.split(","),"Init后台管理系统",content);
            // 存在就再次发送原来的验证码
        } else {
            content = template.render(Dict.create().set("code",oldCode));
            emailVo = new EmailVo(email.split(","),"Init后台管理系统",content);
        }
        return emailVo;
    }

    @Override
    public void validated(String key, String code) {
        Object value = redisUtil.get(key);
        if(value == null || !value.toString().equals(code)){
            throw new HealthException("无效验证码");
        } else {
            redisUtil.del(key);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeStatus(SysEmail sysEmail) {
      // 如果是开启状态
        if(SecurityConstants.IS_OPEN.equals(sysEmail.getStatus())){
            int i = baseMapper.closeAllEmailOpenStatus(sysEmail.getId());
        }
        // 如果是关闭状态
        else {
            List<SysEmail> sysEmails = baseMapper.selectList(new LambdaQueryWrapper<SysEmail>().eq(SysEmail::getStatus, SecurityConstants.IS_OPEN).ne(SysEmail::getId, sysEmail.getId()));
            if(sysEmails.size()<1){
                throw new HealthException("至少要保证一个配置开启");
            }
        }
         return updateById(sysEmail);
    }

    @Override
    public EmailVo sendEmail(EmailDto emailDto) {
        String[] split = emailDto.getToUsers().split(",");
        if (split.length<1){
            throw new HealthException("至少要有一个测试账号");
        }
        for (String s : split) {
            Assert.isTrue(StringUtils.isEmail(s),"邮箱格式错误");
        }
        EmailVo emailVo;
        String content;
        // 如果不存在有效的验证码，就创建一个新的
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("index.ftl");
        content = template.render(Dict.create().set("content",emailDto.getContent()));
        emailVo = new EmailVo(emailDto.getToUsers().split(","),emailDto.getSubject(),content);
        return emailVo;
    }

    public boolean checkFromUserUnique(SysEmail email) {
        Long emailId = StringUtils.isNull(email.getId()) ? -1L : email.getId();
        SysEmail info = baseMapper.selectOne(new LambdaQueryWrapper<SysEmail>().eq(SysEmail::getFromUser, email.getFromUser()));
        if (StringUtils.isNotNull(info) && info.getId().longValue() != emailId.longValue()) {
            return false;
        }
        return true;
    }
}
